
import 'dart:async';
import 'dart:io';

import 'package:flutter/foundation.dart';
import 'package:flutter_bmflocation/flutter_bmflocation.dart';
import 'package:fluttertoast/fluttertoast.dart';

class MapUtils {
  static MapUtils? _instace;

  factory MapUtils() {
    if (_instace == null) {
      _instace = MapUtils._internal();
      _instace!._initState();
    }
    return _instace!;
  }

  MapUtils._internal();

  BaiduLocation? locationResult;
  PropertyListener? propertyListener;
  // late BMFMapController _myMapController;
  LocationFlutterPlugin? _myLocPlugin;
  Timer? _timer;
  bool _suc = false;

  _initState() {
    locationResult = BaiduLocation();
    propertyListener = PropertyListener<BaiduLocation>(BaiduLocation());

    _initPlugin();

    // _initCallback();
  }

  void _initPlugin() async {
    _myLocPlugin = LocationFlutterPlugin();

    Map iosMap = initIOSOptions().getMap();
    Map androidMap = initAndroidOptions().getMap();

    _suc = await _myLocPlugin!.prepareLoc(androidMap, iosMap);
    if (kDebugMode && !_suc) {
      print("插件初始化失败!");
    }
    print("初始化完成");
    _initCallback();
  }

  void startLocation({int timeOut = 0 }) {
    if (_suc == false) {
      _initPlugin();
    }
    print("开始干活");
    // if (Platform.isIOS) {
    //   _myLocPlugin!.singleLocationCallback(callback: (BaiduLocation result) {
    //     locationResult = result;
    //     propertyListener!.value = result;
    //   });
    // } else if (Platform.isAndroid) {
    //   _myLocPlugin!.seriesLocationCallback(callback: (BaiduLocation result) {
    //     print("有结果了");
    //     locationResult = result;
    //     propertyListener!.value = result;
    //     _stopAndroidLocation();
    //   });
    // }

    if (Platform.isIOS) {
      _myLocPlugin!.singleLocation({
        'isReGeocode': true,
        'isNetworkState': true
      });
    } else if (Platform.isAndroid) {
      print("isAndroid");
      _myLocPlugin!.startLocation();
    }

    

    if (timeOut != 0) {
      if (_timer != null) {
        _timer!.cancel();
      }
      Fluttertoast.showToast(msg: "自动循环定位,循环时间: $timeOut");
      _timer = Timer.periodic(Duration(milliseconds: timeOut), (timer) {
        if (Platform.isIOS) {
          _myLocPlugin!.singleLocation({
            'isReGeocode': true,
            'isNetworkState': true
          });
        } else if (Platform.isAndroid) {
          _myLocPlugin!.startLocation();
        }
      });
    } else {
      Fluttertoast.showToast(msg: "单次定位！");
    }
  }

  void _stopAndroidLocation() {
    _myLocPlugin!.stopLocation();
  }

  void stopSeriesLocation() {
    _timer?.cancel();
  }

  void _initCallback() {
    print("初始化回调");
    if (Platform.isIOS) {
      _myLocPlugin!.singleLocationCallback(callback: (BaiduLocation result) {
        locationResult = result;
        propertyListener!.value = result;
      });
    } else if (Platform.isAndroid) {
      _myLocPlugin!.seriesLocationCallback(callback: (BaiduLocation result) {
        print("有结果了");
        locationResult = result;
        propertyListener!.value = result;
        _stopAndroidLocation();
      });
    }
  }

  


  BaiduLocationAndroidOption initAndroidOptions() {
    return BaiduLocationAndroidOption(
      coorType: 'bd09ll',
      locationMode: BMFLocationMode.hightAccuracy,
      isNeedAddress: true,
      isNeedAltitude: true,
      isNeedLocationPoiList: true,
      isNeedNewVersionRgc: true,
      isNeedLocationDescribe: true,
      openGps: true,
      locationPurpose: BMFLocationPurpose.sport,
      coordType: BMFLocationCoordType.bd09ll
    );
  }

  BaiduLocationIOSOption initIOSOptions() {
    return BaiduLocationIOSOption(
      coordType: BMFLocationCoordType.bd09ll,
      BMKLocationCoordinateType: 'BMKLocationCoordinateTypeBMK09LL',
      desiredAccuracy: BMFDesiredAccuracy.best
    );
  }

}

class PropertyListener<T> {
  late T _value;
  late StreamController<T> _controller;

  PropertyListener(T initialValue) {
    _value = initialValue;
    _controller = StreamController<T>.broadcast();
  }

  T get value => _value;

  set value(T newValue) {
    if (_value != newValue) {
      _value = newValue;
      _controller.add(newValue);
    }
  }

  Stream<T> get onChanged => _controller.stream;
}
